package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.Constants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.crypto.MacSpi;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public List<ResourceVo> getResourceList(ResourceDto dto) {
        // 判断缓存中是否有数据
        String list = redisTemplate.opsForValue().get("resourceList");
        if (StringUtils.isNotBlank(list)) {
            //redis缓存中有数据
            log.info("--缓存中有数据--");
            JSONUtil
                    .toList(list, ResourceVo.class)
                    .stream()
                    .filter(vo -> (dto.getResourceNo() == null || vo.getParentResourceNo().equals(dto.getParentResourceNo()))
                            && (dto.getResourceType() == null || vo.getResourceType().equals(dto.getResourceType())))
                    .collect(Collectors.toList());
        }
        log.info("--缓存中没有数据--");
        // 将查询出来的数据放入缓存
        List<ResourceVo> resourceVos = resourceMapper.selectByCondition(dto);
        redisTemplate.opsForValue().set("resourceList", JSONUtil.toJsonStr(resourceVos));
        return resourceVos;
    }

    @Override
    public TreeVo getResourceTree(TreeItemVo itemVo) {
        //获取缓存中的数据
        String resourceTree = redisTemplate.opsForValue().get("resourceTree");
        if (StringUtils.isNotBlank(resourceTree)) {
            //缓存中有数据
            return JSONUtil.toBean(resourceTree, TreeVo.class);
        } else {
            //创建根节点
            TreeItemVo rootItem = new TreeItemVo(SuperConstant.ROOT_PARENT_ID, "智慧养老院", new ArrayList<TreeItemVo>());
            //创建一个dto
            ResourceDto dto = new ResourceDto();
            //设值资源类型
            dto.setResourceType("m");
            //查询所有的一级菜单资源
            List<ResourceVo> voList = resourceMapper.selectByCondition(dto);
            //根据一级菜单 获取子菜单
            createList(voList, rootItem);
            //创建一个集合将添加好的根节点放入集合
            List<TreeItemVo> list = new ArrayList<>();
            list.add(rootItem);
            //创建一个TreeVo
            TreeVo treeVo = new TreeVo(list);
            //查询出数据数据 放入缓存
            redisTemplate.opsForValue().set("resourceTree", JSONUtil.toJsonStr(treeVo));
            return treeVo;
        }
    }

    @Override
    public void addResource(Resource resource) {
        //查询父级资源
        Resource parent = resourceMapper.selectByNo(resource.getParentResourceNo());
        //判断父级状态
        if (!parent.getDataState().equals(resource.getDataState())) {
            //抛出异常
            throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
        }
        //查询子级资源 存在 倒序排序
        List<Resource> list = resourceMapper.selectByParentResourceNo(resource.getParentResourceNo());
        //编号
        String no = "";
        //判断子级资源是否存在
        if (CollectionUtil.isEmpty(list)) {
            //不存在 添加子级资源
            no = NoProcessing.createNo(resource.getParentResourceNo(), false);
        } else {
            //存在 编号+1
            no = NoProcessing.createNo(list.get(0).getResourceNo(), true);
        }
        log.info("----no:{}", no);
        //判断是否为3级
        if (resource.getResourceType().equals("m") &&
                no.endsWith("000")) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        //添加 设置no
        resource.setResourceNo(no);
        resourceMapper.insert(resource);
        //更改了数据库 需要删除缓存
        redisTemplate.delete("resourceList");
        redisTemplate.delete("resourceTree");
    }

    @Override
    public void updateResource(Resource resource) {
        resourceMapper.updateByPrimaryKey(resource);
    }

    @Override
    public void disableResource(ResourceDto dto) {
        Resource resource = BeanUtil.toBean(dto, Resource.class);
        String resourceNo = dto.getResourceNo();
        //判断是否为按钮
        if (!resourceNo.endsWith("000")) {
            //判断状态
            if ("1".equals(dto.getDataState())) {
                resource.setDataState("0");
            } else {
                resource.setDataState("1");
            }
            //为按钮 直接更改当前资源的状态
            resourceMapper.updateByPrimaryKey(resource);
        } else {
            //获取当前父资源的下的所有的菜单资源
            dto.setResourceType("m");
            //查询所有的一级菜单资源
            List<ResourceVo> voList = resourceMapper.selectByCondition(dto);
            //创建孩子节点
            TreeItemVo itemVo = new TreeItemVo(dto.getResourceNo(), dto.getResourceName(), new ArrayList<TreeItemVo>());
            //查找子资源更改其状态
            List<String> noList = searchResource(voList,itemVo);
            //
        }
    }

    @Override
    public List<MenuVo> getResourceMenus() {
        //获取用户id
        Long userId = UserThreadLocal.getMgtUserId();
        //获取用户资源
        List<MenuVo> menuVos = resourceMapper.findResourceMenus(userId);
//        log.info("菜单列表:{}",menuVos);
        //将父编号对应的子编号找出来 结构Map<String,List<MenusVo>>
//        Map<String, List<MenuVo>> map = new HashMap<>();
//        for (MenuVo vo : menuVos) {
//            //获取子编号
//            String resourceNo = vo.getResourceNo();
//            for (MenuVo menuVo : menuVos) {
//                //如果父编号和子编号一致
//                if (menuVo.getParentResourceNo().equals(resourceNo)) {
//                        if (map.containsKey(resourceNo)) {
//                            //map集合中的键存在则直接添加
//                            vo.getChildren().add(menuVo);
//                        }else {
//                            //map集合中的键不存在则创建一个集合用于添加
//                            ArrayList<MenuVo> list = new ArrayList<>();
//                            list.add(menuVo);
//                            map.put(resourceNo,list);
//                        }
//                }
//            }
//        }
        Map<String, List<MenuVo>> map = menuVos.stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        log.info("父编号和其子编号的map集合:{}",map);
        //构造集合
        for (MenuVo menuVo : menuVos) {
            String resourceNo = menuVo.getResourceNo();
            menuVo.setRedirect("/" + menuVo.getName());
            menuVo.setMeta(new MenuMetaVo(menuVo.getName(), null, null));
            //获取编号的子资源
            List<MenuVo> menuVoList = map.get(resourceNo);
            //判断集合是否为空
            if (!CollectionUtil.isEmpty(menuVoList)){
                for (MenuVo vo : menuVoList) {
                    vo.setMeta(new MenuMetaVo(vo.getName(), null, null));
                    vo.setRedirect(menuVo.getRedirect() + "/" + vo.getName());
                }
                menuVo.setChildren(menuVoList);
            }
        }
        return map.get(SuperConstant.ROOT_PARENT_ID);
    }

    @Override
    public List<String> findButListByUserId(Long userId) {
        return resourceMapper.findButListByUserId(userId);
    }

    @Override
    public List<String> findAllButResource() {
        return resourceMapper.findAllButResource();
    }


    /**
     * 递归查找子资源 返回一个集合
     * @param voList
     * @param itemVo
     * @return
     */
    private List<String> searchResource(List<ResourceVo> voList, TreeItemVo itemVo) {
        //创建一个集合用于存取子资源的编号
        ArrayList<String> noList = new ArrayList<>();
        //递归进行树形结构的查找
        for (ResourceVo vo : voList) {
            //根据编号匹配父节点
            if (vo.getParentResourceNo().equals(itemVo.getId())){
                TreeItemVo voRoot = new TreeItemVo(vo.getResourceNo(), vo.getResourceName(), new ArrayList<TreeItemVo>());
                //添加编号到集合
                noList.add(vo.getResourceNo());
                //递归
                searchResource(voList,voRoot);
            }
        }
        return noList;
    }



    /**
     * 循环遍历树形结构
     *
     * @param voList
     * @param rootItem
     */
    private void createList(List<ResourceVo> voList, TreeItemVo rootItem) {
        //使用递归进行树结构
        for (ResourceVo vo : voList) {
            if (vo.getParentResourceNo().equals(rootItem.getId())
                    && vo.getResourceNo().endsWith("000")) {
                //创建一个子级菜单
                TreeItemVo itemVo = new TreeItemVo(vo.getResourceNo(), vo.getResourceName(), new ArrayList<TreeItemVo>());
                //将子级菜单添加到根节点
                rootItem.getChildren().add(itemVo);
                //循环遍历
                createList(voList, itemVo);
            }
        }
    }
}
